﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Xms.Abp.BackgroundJob;
using Xms.Abp.Domain;
using Xms.Abp.Domain.Repositories;

namespace BackgroundJobManagement;

[Dependency(ReplaceServices = true)]
public class BackgroundScheduleStore : XmsDomainService, IBackgroundScheduleStore, ITransientDependency
{
    protected IXmsRepository<BackgroundScheduleEntity, Guid> Repository
        => LazyInject<IXmsRepository<BackgroundScheduleEntity, Guid>>();
    protected IDataFilter<ISoftDelete> DataFilter
        => LazyInject<IDataFilter<ISoftDelete>>();

    public async Task DeleteAsync(string scheduleName, CancellationToken cancellationToken = default)
    {
        if (Guid.TryParse(scheduleName, out Guid id))
        {
            await Repository.DeleteAsync(id, true, cancellationToken);
        }
        else
        {
            await Repository.DeleteAsync(r => r.Name == scheduleName, true, cancellationToken);
        }
    }

    public async Task<BackgroundScheduleInfo> FindAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var entity = await Repository.FindAsync(id, cancellationToken: cancellationToken);
        return ObjectMapper.MapTo<BackgroundScheduleInfo>(entity);
    }

    public async Task<BackgroundScheduleInfo> FindAsync(string scheduleName, CancellationToken cancellationToken = default)
    {
        var entity = await Repository.FindAsync(r => r.Name == scheduleName, cancellationToken: cancellationToken);
        return ObjectMapper.MapTo<BackgroundScheduleInfo>(entity);
    }

    public async Task<List<BackgroundScheduleInfo>> GetAllSchedulesAsync(CancellationToken cancellationToken = default)
    {
        var list = await (await Repository.AsNoTrackingAsync()).ToListAsync(cancellationToken);
        return ObjectMapper.MapTo<BackgroundScheduleInfo>(list);
    }

    public async Task<List<BackgroundScheduleInfo>> GetModifiedSchedulesAsync(DateTime lastCheckTime, CancellationToken cancellationToken = default)
    {
        var list = await (await Repository.AsNoTrackingAsync()).Where(r => r.ModificationTime > lastCheckTime).ToListAsync(cancellationToken);
        return ObjectMapper.MapTo<BackgroundScheduleInfo>(list);
    }

    public async Task<List<BackgroundScheduleInfo>> GetDeletedSchedulesAsync(DateTime lastCheckTime, CancellationToken cancellationToken = default)
    {
        using (DataFilter.Disable())
        {
            var list = await (await Repository.AsNoTrackingAsync()).Where(r => r.DeletionTime > lastCheckTime && r.IsDeleted).ToListAsync(cancellationToken);
            return ObjectMapper.MapTo<BackgroundScheduleInfo>(list);
        }
    }

    public async Task InsertAsync(BackgroundScheduleInfo scheduleInfo, CancellationToken cancellationToken = default)
    {
        var entity = new BackgroundScheduleEntity(GuidGenerator.Create());
        ObjectMapper.Map(scheduleInfo, entity);
        await Repository.InsertAsync(entity, true, cancellationToken);
    }

    public async Task UpdateAsync(BackgroundScheduleInfo scheduleInfo, CancellationToken cancellationToken = default)
    {
        var backgroundScheduleRecord = await Repository.FindAsync(r => r.Name == scheduleInfo.Name, cancellationToken: cancellationToken);
        if (backgroundScheduleRecord == null)
        {
            return;
        }

        ObjectMapper.Map(scheduleInfo, backgroundScheduleRecord);
        await Repository.UpdateAsync(backgroundScheduleRecord, true, cancellationToken);
    }
}
